package com.sh.data.engine.domain.dataasset.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yitter.idgen.YitIdHelper;
import com.sh.data.engine.common.enumDefinition.DSType;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.common.util.TableNameUtil;
import com.sh.data.engine.domain.base.model.PageResult;
import com.sh.data.engine.domain.dataasset.model.domain.DataAssetDomain;
import com.sh.data.engine.domain.dataasset.model.enums.ModelLevelEnum;
import com.sh.data.engine.domain.dataasset.model.param.SaveNewTblPropParam;
import com.sh.data.engine.domain.dataasset.service.TblPropService;
import com.sh.data.engine.domain.dataasset.service.TblService;
import com.sh.data.engine.domain.integration.datasource.model.domain.DataSourceDetailDomain;
import com.sh.data.engine.domain.integration.datasource.service.DataSourceService;
import com.sh.data.engine.domain.shims.db.model.TableInfoDomain;
import com.sh.data.engine.repository.dao.dataasset.TblPropMapper;
import com.sh.data.engine.repository.dao.dataasset.entity.TblPropEntity;
import com.sh.data.engine.repository.dao.integration.datasource.entity.DataSourceEntity;
import com.sh.data.engine.repository.dao.integration.datasource.entity.DataSourceEntity.RdbmsConfig;
import com.sh.data.engine.repository.dao.normalization.research.themedesign.entity.ThemeEntity;
import com.sh.data.engine.repository.dao.workspace.index.entity.ProjectEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author: mengzheng.mhc
 * @date: 2024/6/19 12:26
 */
@Service
@Slf4j
public class TblPropServiceImpl extends ServiceImpl<TblPropMapper, TblPropEntity>
    implements TblPropService {

    @Lazy
    @Autowired
    private TblService tblService;

//    @Lazy
//    @Autowired
//    private UserService userService;

    @Lazy
    @Autowired
    private DataSourceService dataSourceService;

    @Override
    public List<TblPropEntity> findByTblpropId(Collection<Long> themeId) {

        LambdaQueryWrapper<TblPropEntity> lambdaQueryWrapper =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getRowState, 1)
                .in(TblPropEntity::getThemeId, themeId);
        List<TblPropEntity> multi = this.list(lambdaQueryWrapper);
        return multi;
    }

    @Override
    public TblPropEntity getTblPropByTblId(Long projectId, Long tblId) {

        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(Objects.nonNull(projectId), TblPropEntity::getProjectId, projectId)
                .eq(TblPropEntity::getRowState, 1)
                .eq(TblPropEntity::getTblId, tblId);
        return this.getOne(eq);
    }

    @Override
    public List<TblPropEntity> getTblPropByThemeId(Long themeId) {
        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getRowState, 1)
                .eq(TblPropEntity::getThemeId, themeId);
        return this.list(eq);
    }

    @Override
    public List<TblPropEntity> getTblPropByThemeIdList(List<Long> themeIdList) {

        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getRowState, 1)
                .in(TblPropEntity::getThemeId, themeIdList);
        return this.list(eq);
    }

    /**
     * sap query schema
     *
     * @param projectId
     * @param schema
     * @param tblName
     * @return
     */
    @Override
    public TblPropEntity getTblPropByTblName(Long projectId, String schema, String tblName) {
        DataSourceDetailDomain dataSourceDetailByProjectId =
            dataSourceService.getDataSourceDetailByProjectId(projectId, false);
        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getProjectId, projectId)
                .eq(TblPropEntity::getRowState, 1)
                .in(TblPropEntity::getTableName, tblName);

        String dsType = dataSourceDetailByProjectId.getDsType();
        if (DSType.hasSchema(dsType)) {
            eq.eq(TblPropEntity::getSchema, dataSourceDetailByProjectId.getRdbmsConfig().getSchema());
        }
        if (StringUtils.isNotBlank(schema)) {
            eq.eq(TblPropEntity::getSchema, schema);
        }
        final TblPropEntity tblPropEntity = this.getOne(eq, false);
        return tblPropEntity;
    }

    /**
     * 不支持表名带.的查询
     *
     * @param projectId
     * @param tblName
     * @return
     */
    @Override
    public TblPropEntity getTblPropByTblName(Long projectId, String tblName) {
        String tblNameShort = TableNameUtil.getTblNameShort(tblName);

        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getProjectId, projectId)
                .eq(TblPropEntity::getRowState, 1)
                .in(TblPropEntity::getTableName, tblNameShort);
        final TblPropEntity tblPropEntity = this.getOne(eq, false);
        return tblPropEntity;
    }

    @Override
    public TblPropEntity getTblPropBySchemaTblName(Long projectId, String schema, String tblName) {
        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getProjectId, projectId)
                .eq(TblPropEntity::getRowState, 1)
                .eq(StringUtils.isNotEmpty(schema), TblPropEntity::getSchema, schema)
                .eq(TblPropEntity::getTableName, tblName);
        return this.getOne(eq);
    }

    /**
     * @param projectId
     * @param pageNum
     * @param pageSize
     * @param themeIds
     * @param search
     * @return
     */
    @Override
    public PageResult<TblPropEntity> getTblPropPage(
        Long projectId,
        Integer pageNum,
        Integer pageSize,
        List<Long> themeIds,
        List<String> tableNames,
        String search,
        String orderField,
        String order) {

        LambdaQueryWrapper<TblPropEntity> lambdaQueryWrapper =
            new LambdaQueryWrapper<>(TblPropEntity.class)
                .eq(TblPropEntity::getProjectId, projectId)
                .eq(TblPropEntity::getRowState, 1);
        if (StringUtils.isNotBlank(orderField) && StringUtils.isNotBlank(order)) {
            lambdaQueryWrapper.last("order by " + orderField + " " + order);
        }
        if (CollectionUtils.isNotEmpty(themeIds)) {
            lambdaQueryWrapper.in(TblPropEntity::getThemeId, themeIds);
        }
        if (CollectionUtils.isNotEmpty(tableNames)) {
            lambdaQueryWrapper.in(TblPropEntity::getTableName, tableNames);
        }
        if (StringUtils.isNotBlank(search)) {
            lambdaQueryWrapper.like(TblPropEntity::getTableName, search);
        }

        Page<TblPropEntity> page = this.page(new Page<>(pageNum, pageSize), lambdaQueryWrapper);
        PageResult<TblPropEntity> convert = PageResult.convert(page);
        return convert;
    }

    /**
     * 新建模型时创建表
     *
     * @param saveNewTblPropParam
     * @return
     */
    @Override
    public TblPropEntity saveNewTblPropEntity(SaveNewTblPropParam saveNewTblPropParam) {
        TblPropEntity tblPropEntity = new TblPropEntity();
        ProjectEntity projectEntity = new ProjectEntity();
        projectEntity.setId(saveNewTblPropParam.getProjectId());
        tblPropEntity.setTableName(saveNewTblPropParam.getTableName());
        tblPropEntity.setTableComment(saveNewTblPropParam.getTableComment());
        tblPropEntity.setLifecycle(saveNewTblPropParam.getLifeCycle());
        tblPropEntity.setSchema(saveNewTblPropParam.getSchema());
        tblPropEntity.setTblId(saveNewTblPropParam.getTblId());
        ThemeEntity themeEntity = new ThemeEntity();
        themeEntity.setId(saveNewTblPropParam.getThemeId());
        tblPropEntity.setTblType(saveNewTblPropParam.getTblType());
        tblPropEntity.setThemeId(saveNewTblPropParam.getThemeId());
        tblPropEntity.setProjectId(saveNewTblPropParam.getProjectId());
        tblPropEntity.setRowState(1);
        tblPropEntity.setCreatorId(saveNewTblPropParam.getCreatorId());
        tblPropEntity.setDataSecretId(saveNewTblPropParam.getDataSecretId());
        this.save(tblPropEntity);
        return tblPropEntity;
    }

    @Override
    public List<TblPropEntity> getTblPropListByIdList(Long projectId, List<Long> idList) {
        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getProjectId, projectId)
                .in(CollectionUtils.isNotEmpty(idList), TblPropEntity::getId, idList)
                .eq(TblPropEntity::getRowState, 1);
        List<TblPropEntity> resultList = this.list(eq);
        return resultList;
    }

    @Override
    public List<TblPropEntity> getTblPropListByTblNameList(Long projectId, List<String> tblNameList) {
        if (CollectionUtils.isEmpty(tblNameList)) {
            return Collections.EMPTY_LIST;
        }
        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getProjectId, projectId)
                .eq(TblPropEntity::getRowState, 1)
                .in(TblPropEntity::getTableName, tblNameList);

        List<TblPropEntity> resultList = this.list(eq);
        return resultList;
    }

    @Override
    public TblPropEntity getTblPropById(Long id) {

        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getId, id)
                .eq(TblPropEntity::getRowState, 1);
        return this.getOne(eq);
    }

    @Override
    public List<TblPropEntity> getTblPropByProjectId(Long projectId) {

        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getProjectId, projectId)
                .eq(TblPropEntity::getRowState, 1);
        List<TblPropEntity> list = this.list(eq);
        return list;
    }

    @Override
    public List<TblPropEntity> getAllTblPropByProjectId(Long projectId) {

        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getProjectId, projectId)
                .eq(TblPropEntity::getRowState, 1);
        List<TblPropEntity> list = this.list(eq);
        return list;
    }

    @Override
    public DataAssetDomain getDataAssetCount(Long projectId) {
        Map<String, Integer> tableMap = tblService.getTableCount(projectId);
        List<TblPropEntity> list = getAllTblPropByProjectId(projectId);

        List<DataAssetDomain.Item> items = new ArrayList<>();
        DataAssetDomain domain = new DataAssetDomain();
        if (null != list) {
            domain.setTotal(list.size());
        } else {
            domain.setTotal(0);
        }
        for (ModelLevelEnum levelEnum : ModelLevelEnum.values()) {
            DataAssetDomain.Item item = new DataAssetDomain.Item();
            if (tableMap.containsKey(levelEnum.getCode())) {
                item.setName(levelEnum.getName());
                item.setLevel(levelEnum.getCode());
                item.setCount(tableMap.get(levelEnum.getCode()));
            } else {
                item.setName(levelEnum.getName());
                item.setLevel(levelEnum.getCode());
                item.setCount(0);
            }
            items.add(item);
        }
        domain.setItems(items);
        return domain;
    }

    @Override
    public boolean updateTblPropById(TblPropEntity entity) {
        return this.updateById(entity);
    }

    @Override
    public void updateBatch(List<TblPropEntity> entities) {
        if (CollectionUtils.isEmpty(entities)) {
            return;
        }

        //    List<BathUpdateOptions> options = new ArrayList<>();
        //
        //    for (TblPropEntity entity : entities) {
        //      final Criteria criteria =
        //          Criteria.where("projectId")
        //              .is(entity.getProjectId())
        //              .and("schema") // sap different schema
        //              .is(entity.getSchema())
        //              .and("tableName")
        //              .is(entity.getTableName());
        //      Query query = new Query(criteria);
        //
        //      Update update = new Update();
        //      update.set("tblId", entity.getTblId());
        //      update.set("rowState", entity.getRowState());
        //      update.set("tableComment", entity.getTableComment());
        //
        //      options.add(new BathUpdateOptions(query, update, false, true));
        //    }
        this.updateBatchById(entities);
    }

    @Override
    public void insertBatch(List<TblPropEntity> entities) {
        if (CollectionUtils.isEmpty(entities)) {
            return;
        }

        this.saveBatch(entities);
    }

    @Override
    public String getSecretLevel(String tableName, Long projectId) {
        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getTableName, tableName)
                .eq(TblPropEntity::getRowState, 1)
                .eq(TblPropEntity::getProjectId, projectId);
        TblPropEntity one = this.getOne(eq, false);

        if (Objects.nonNull(one)) {
            Long dataSecretId = one.getDataSecretId();
            if (Objects.nonNull(dataSecretId)) {
//                SecretMgtEntity byId = secretMgtService.getById(dataSecretId);
//                if (Objects.nonNull(byId)) {
//                    return byId.getSecretName();
//                }
            }
        }
        return null;
    }

    @Override
    public Long generateTblId(Long projectId) {
        // 采用雪花算法生成唯一id
        return YitIdHelper.nextId();
    }

    @Override
    public List<TblPropEntity> getMatrixTblProp(Long projectId, Long themeId, String type) {

        if (!"dim".equals(type) && !"dwd".equals(type)) {
            throw new BusinessException("unknown model type");
        }

        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getProjectId, projectId)
                .eq(TblPropEntity::getThemeId, themeId)
                .eq(TblPropEntity::getRowState, 1)
                .likeLeft(StringUtils.equals(type, "dim"), TblPropEntity::getTableName, "dim%")
                .and(
                    StringUtils.equals(type, "dwd"),
                    e ->
                        e.likeLeft(TblPropEntity::getTableName, "dwd%")
                            .or()
                            .likeLeft(TblPropEntity::getTableName, "dws%"));

        return list(eq);
    }

    /**
     * cdm指标来源表 查dwd开头的表
     *
     * @param projectId
     * @param themeId
     * @param type
     * @return
     */
    @Override
    public List<TblPropEntity> getCdmQuotaSourceTable(Long projectId, Long themeId, String type) {
        if (!"dwd".equals(type)) {
            throw new BusinessException("unknown model type");
        }
        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getProjectId, projectId)
                .eq(!Objects.isNull(themeId), TblPropEntity::getThemeId, themeId)
                .eq(TblPropEntity::getRowState, 1)
                .likeLeft(TblPropEntity::getTableName, "dwd%");
        return list(eq);
    }

    @Override
    public void deleteTbl(Long projectId, Long tblId) {
        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getProjectId, projectId)
                .eq(TblPropEntity::getTblId, tblId);
        this.remove(eq);
    }

    @Override
    public List<TblPropEntity> getListByPage(Long projectId, Integer pageSize, Integer pageNum) {

        LambdaQueryWrapper<TblPropEntity> eq =
            new LambdaQueryWrapper<TblPropEntity>()
                .eq(TblPropEntity::getProjectId, projectId)
                .eq(TblPropEntity::getRowState, 1);

        Page<TblPropEntity> page = page(new Page<>(pageNum, pageSize), eq);
        return page.getRecords();
    }

    public static void main(String[] args) {
    }

    @Override
    public boolean checkSecretLevel(String table, Long projectId, String userId) {
        log.warn("不支持数据密级校验");
        return true;
//        UserDomain userById = userService.getUserById(userId);
//
//        String schema = null;
//        if (table.contains(".")) {
//            String[] split = table.split("\\.", 2);
//            schema = split[0];
//            table = split[1];
//        }
//        table = table.replaceAll("[\"']", "");
//        LambdaQueryWrapper<TblPropEntity> eq =
//            new LambdaQueryWrapper<TblPropEntity>()
//                .eq(TblPropEntity::getTableName, table)
//                .eq(TblPropEntity::getRowState, 1)
//                .eq(TblPropEntity::getProjectId, projectId);
//        if (StringUtils.isNotBlank(schema)) {
//            schema = schema.replaceAll("[\"']", "");
//            eq.eq(TblPropEntity::getSchema, schema);
//        }
//        TblPropEntity one = this.getOne(eq, false);
//
//        if (Objects.isNull(userById) || Objects.isNull(one) || Objects.isNull(one.getDataSecretId())) {
//            return true;
//        }
//
//        boolean b =
//            secretMgtService.validSecretLevel(userById.getSecurityLevelId(), one.getDataSecretId());
//        return b;
    }

    @Override
    public void createTableSecret(List<String> tables, Long projectId, String userId) {

        DataSourceEntity sourceEntity = dataSourceService.getSystemDataSourceDetail(projectId);
        RdbmsConfig rdbmsConfig = sourceEntity.getRdbmsConfig();

        String schema = null;
        if (Objects.nonNull(rdbmsConfig)) {
            schema = rdbmsConfig.getSchema();
        }
        // 写在for循环里面即可。list最多只有一条数据，不要优化！！！
        for (String table : tables) {
            Long dataSecretId = null;
//            UserDomain userDomain = userService.getUserById(userId);
//            Long securityLevelId = userDomain.getSecurityLevelId();
//            if (Objects.isNull(securityLevelId)) {
//                return;
//            }
//            SecretMgtEntity userSecret = secretMgtService.getById(securityLevelId);
//            SecretMgtEntity one =
//                secretMgtService.getOne(
//                    new LambdaQueryWrapper<>(SecretMgtEntity.class)
//                        .ge(SecretMgtEntity::getPriority, userSecret.getPriority())
//                        .eq(SecretMgtEntity::getSecretType, 1)
//                        .ne(SecretMgtEntity::getRowState, 0)
//                        .orderByAsc(SecretMgtEntity::getPriority),
//                    false);
//            if (Objects.nonNull(one)) {
//                dataSecretId = one.getId();
//            }
            // 先判断表是否存在 是否存在密级
            if (table.contains(".")) {
                String[] split = table.split("\\.", 2);
                String schema1 = split[0].replaceAll("[\"']", "");
                if (StringUtils.isNotBlank(schema1)) {
                    if (!Objects.equals(schema, schema1)) {
                        return;
                    }
                }
                table = split[1].replaceAll("[\"']", "");
            }
            TblPropEntity tblPropEntity =
                this.getOne(
                    new LambdaQueryWrapper<>(TblPropEntity.class)
                        .eq(TblPropEntity::getProjectId, projectId)
                        .eq(TblPropEntity::getTableName, table)
                        .eq(TblPropEntity::getRowState, 1));
            if (Objects.isNull(tblPropEntity)) {
                TblPropEntity tblProp = new TblPropEntity();
                tblProp.setProjectId(projectId);
                tblProp.setSchema(schema);
                tblProp.setTblId(this.generateTblId(projectId));
                tblProp.setDataSecretId(dataSecretId);
                tblProp.setTableName(table);
                tblProp.setLifecycle(-1);
                tblProp.setTblType(TableInfoDomain.TblType.MANAGED_TABLE.name());
                tblProp.setRowState(1);
                tblProp.setCreatorId(userId);
                tblProp.setUpdaterId(userId);
                this.save(tblProp);
            } else if (Objects.nonNull(tblPropEntity)) {
                tblPropEntity.setDataSecretId(dataSecretId);
                this.updateById(tblPropEntity);
            }
        }
    }
}
